<?php
/**
 * @Project OpenID - ĐQC
 * @Author Tiến Thành (tienthanh@dinhquanclub.tk)
 * @Copyright (C) 2012 Định Quán Club All rights reserved
 */

/**
 * FloodBlocker 
 * @author Tiến Thành
 * @copyright Định Quán Club
 * @version 2012
 * @access public
 */

class FloodBlocker
{
	/**
	 * FloodBlocker::__construct()
	 * 
	 * @param mixed $ip_logs
	 * @param string $ip
	 * @return void
	 */
	public function __construct( $ip_logs, $ip = '' )
	{
		// Kiểm tra có thư mục chứa file ip không
		if( ! is_dir( $ip_logs ) ) die( 'Có lỗi! Thư mục '.$ip_logs.' không tồn tại' );

		//Nếu chưa nhập biến ip thì ta tự xác định giá trị $ip = $_SERVER['REMOTE_ADDR']
		if( empty( $ip ) ) $ip = $_SERVER['REMOTE_ADDR'];
		
		// Thêm '/' vào $ip_logs nếu chưa có
		if( substr( $ip_logs, -1 ) != '/' ) $ip_logs .= '/';

		$this->CheckFlood($ip_logs, $this->get_ip());

	}

	/**
	 * FloodBlocker::CheckFlood()
	 */
	private function CheckFlood($ip_logs, $ip , $max_lockcount=10, $max_connect=1, $time_limit=3, $time_wait=1, $email='admin@dinhquanclub.tk', $htaccess = '.htaccess')
	{
		$now=time();
		if (file_exists("$ip_logs/$ip".'.deny')) // Nếu bị cấm vĩnh viễn
		{
			//Cấm bằng htaccess
			@chmod($htaccess, 0666);
			@$ft=fopen($htaccess,'a');
			@fwrite($ft,"deny from $ip\n");
			@fclose($ft);
			show_message("IP của bạn <font color='red'>$ip</font> đã bị khóa truy cập để đảm bảo an toàn (Do hệ thông phát hiện dấu hiệu Flood nhiều lần từ IP của bạn).<br />Vui lòng sử dung email lúc bạn đã đăng kí thành viên liên lạc với BQT (Nhớ gửi kèm tên tài khoản),<br /> qua email <a href='mailto:{$email}'>{$email}</a> để bỏ khóa cho ip bạn(Nếu ko, IP sẽ dc tự mở khóa sau 24h)",-1);
		}
		elseif (file_exists("$ip_logs/$ip".'.lock')) // Nếu bị khóa tạm thời
		{
			@chmod("$ip_logs/$ip".'.lock', 0666);
			@$time=file_get_contents("$ip_logs/$ip".'.lock');

			if (file_exists("$ip_logs/$ip".'.lockcount')) $lock_count=file_get_contents("$ip_logs/$ip".'.lockcount');
			else $lock_count=0;

			$wait=(($time_wait*($lock_count+1))+$time)-$now;
			if ($wait>0) // Nếu chưa hết hạn khóa
			{
				$this->show_message("IP của bạn <font color='red'>$ip</font> đã bị khóa truy cập $lock_count lần.",$wait);
			}
			else // Nếu không thì bỏ khóa tạm thời
			{
				@unlink("$ip_logs/$ip".'.lock');
				@chmod("$ip_logs/$ip", 0666);
				@$ft=fopen("$ip_logs/$ip",'w');
				@fwrite($ft,"1|".$now);
				@fclose($ft);
			}
		}
		else // Nếu là IP mới
		{
			// Duyệt lại xem IP đã truy cập lần nào chưa
			if (file_exists("$ip_logs/$ip"))
			{
				// Nếu đã truy cập thì kiểm tra số kết nối
				@chmod("$ip_logs/$ip", 0666);
				@$c=file_get_contents("$ip_logs/$ip");
				$dinhquanclub=explode('|',$c);
				$con=$dinhquanclub[0];
				$firttime=$dinhquanclub[1];
				if (($con+1)>=$max_connect && ($now-$firttime)<=$time_limit)
				{
					// Nếu số kết nối lớn hơn giới hạn --> lock	
					@chmod("$ip_logs/$ip".'.lock', 0666);							
					$ft=fopen("$ip_logs/$ip".".lock",'w');
					fwrite($ft,$now);
					fclose($ft);
						// Đếm số lượt kết nối & nếu quá giới hạn thì --> lock vĩnh viễn
						if (file_exists("$ip_logs/$ip".'.lockcount'))
						{
							@chmod("$ip_logs/$ip".'.lockcount', 0666);
							@$lock_count=file_get_contents("$ip_logs/$ip".'.lockcount');
							
						}
						else
							$lock_count=0;
						if (($lock_count+1)>=$max_lockcount)
						{
							// Tăng số lần khóa tạm lên
							@chmod("$ip_logs/$ip".'.lockcount', 0666);	
							@$ft=fopen("$ip_logs/$ip".".lockcount",'w');
							@fwrite($ft,$lock_count+1);
							@fclose($ft);
							// Khóa bằng firewall
							@chmod("$ip_logs/$ip".'.deny', 0666);	
							@$ft=fopen("$ip_logs/$ip".'.deny','w');
							@fclose($ft);
							// Khóa bằng HTACCESS --> 403
							@chmod($htaccess, 0666);
							@$ft=fopen($htaccess,'a');
							@fwrite($ft,"deny from $ip\n");
							@fclose($ft);
							// Báo cho họ biết họ bị khóa
							show_message("IP của bạn <font color='red'>$ip</font> đã bị khóa truy cập để đảm bảo an toàn (Do hệ thông phát hiện dấu hiệu Flood nhiều lần từ IP của bạn).<br />Vui lòng sử dung email lúc bạn đã đăng kí thành viên liên lạc với BQT (Nhớ gửi kèm tên tài khoản),<br /> qua email <a href='mailto:{$email}'>{$email}</a> để bỏ khóa cho ip bạn(Nếu ko, IP sẽ dc tự mở khóa sau 24h)",-1);
						}
						else
						{
							@chmod("$ip_logs/$ip".'.lockcount', 0666);	
							@$ft=fopen("$ip_logs/$ip".'.lockcount','w');
							@fwrite($ft,$lock_count+1);
							@fclose($ft);
							@$time=file_get_contents("$ip_logs/$ip".'.lock');
							$wait=(($time_wait*($lock_count+1))+$time)-$now;
							// Báo cho họ biết họ bị khóa
							$this->show_message('IP của bạn <font color=\'red\'>'.$ip.'</font> đã bị khóa truy cập '.$lock_count.' lần.', $wait);
						}
				}
				elseif (($con+1)<$max_connect && ($now-$firttime)>=$time_limit)
				{
				// Nếu đã lâu rồi thì reset lại thời gian
				@chmod("$ip_logs/$ip", 0666);	
				@$ft=fopen("$ip_logs/$ip",'w');
				@fwrite($ft,"1|".$now);
				@fclose($ft);
				}
				else
				{
					@chmod("$ip_logs/$ip", 0666);	
					@$ft=fopen("$ip_logs/$ip",'w');
					@fwrite($ft,($con+1)."|".$now);
					@fclose($ft);
				}
			}
			else
			{
				// Nếu IP này chưa từng truy cập
				@chmod("$ip_logs/$ip", 0666);	
				@$ft=fopen("$ip_logs/$ip",'w');
				@fwrite($ft,"1|".$now);
				@fclose($ft);
			}
		}
	}
	
	/**
	 * FloodBlocker::get_ip()
	 * 
	 * @return $ip
	 */
	private function get_ip()
	{
		# Enable X_FORWARDED_FOR IP matching?
		$do_check = 0;
		$addrs = array();

		if( $do_check )
		{
			foreach( array_reverse(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])) as $x_f )
			{
				$x_f = trim($x_f);
				if( preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $x_f) )
				{
					$addrs[] = $x_f;
				}
			}

			$addrs[] = $_SERVER['HTTP_CLIENT_IP'];
			$addrs[] = $_SERVER['HTTP_PROXY_USER'];
		}

		$addrs[] = $_SERVER['REMOTE_ADDR'];

		foreach( $addrs as $v )
		{
			if( $v )
			{
				preg_match("/^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/", $v, $match);
				$ip = $match[1].'.'.$match[2].'.'.$match[3].'.'.$match[4];

				if( $ip && $ip != '...' )
				{
					break;
				}
			}
		}

		if( ! $ip || $ip == '...' )
		{
			show_message("Sự truy cập của bạn bị từ chối vì IP của bạn ko hợp lệ.");
			exit();
		}

		return $ip;
	}

	/**
	 * FloodBlocker::loadTemplate()
	 */
	private function loadTemplate( $path, $vars="" )
	{
		if(is_array($vars) && count($vars) > 0) extract($vars, EXTR_PREFIX_SAME, "wddx");
		require_once( $path );
	}

	/**
	 * FloodBlocker::show_message()
	 */
	private function show_message($msg,$time=60)
	{
		//Nạp dữ liệu vào html
		$data = array(
			'msg' => $msg,
			'time' => $time,
		); 

		$this->loadTemplate('flood_blocker.html', $data);
		exit();
	}
	
	/**
	 * FloodBlocker::clear_data()
	 */
	private function clear_data($dir)
	{
		if ( $dirHandle = opendir($dir) ) {
			while ( $file = readdir($dirHandle) ) {
				if ( $file !== "." && $file !== ".." ) {
					if (basename($file)!=".htaccess")
						@unlink($dir."/".$file);
				}
			}
			closedir($dirHandle);
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * FloodBlocker::unlock_all()
	
	function unlock_all($ip_logs, $htaccess_data='')
	{
		$ft=fopen('.htaccess','w');
		fwrite($ft, $htaccess_data);
		fclose($ft);
		//Bo cam tren Firewall
		$this->clear_data($ip_logs);
	}*/
	
}

?>